package com.xxx.springboot.controller;

import java.lang.reflect.Field;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import sun.misc.Unsafe;

/**
 * 测试 Unsafe
 */
@Controller
@RequestMapping(value = "/", produces = "application/json;charset=utf-8")
public class TestUnsafeController {
	
//	private static Unsafe unsafe = null;
//	static {
//	    try {
//	    	Field field = Unsafe.class.getDeclaredField("theUnsafe");
//	    	field.setAccessible(true);
//	        unsafe = (Unsafe) field.get(null);
//	    } catch (NoSuchFieldException e) {
//	        e.printStackTrace();
//	    } catch (IllegalAccessException e) {
//	        e.printStackTrace();
//	    }
//	}

    /**
     * Unsafe作用一：操纵对象属性
     */
    @RequestMapping("/testUnsafe1")
    @ResponseBody
    public User testUnsafe1(String name1) {
    	User user = new User();
		user.setId(1);
		user.setName("zhangsan");
		user.setAge(10);
		System.out.println("user1:" + user.toString());
		
		try {
			// 获取Unsafe类实例方法一：直接获取Unsafe类提供的获取单例方法（java.lang.SecurityException: Unsafe）
//			Unsafe unsafe = Unsafe.getUnsafe();
			
			// 获取Unsafe类实例方法二：通过反射获取（也可以将放到静态成员里）
			Field field = Unsafe.class.getDeclaredField("theUnsafe");
			field.setAccessible(true);
			Unsafe unsafe = (Unsafe)field.get(null);
			
			// 获取User类自己定义的属性name
			Field name_field = user.getClass().getDeclaredField("name");
			
			// 通过Unsafe.objectFieldOffset()方法获取非静态属性name的值的内存偏移地址
			long name_offset = unsafe.objectFieldOffset(name_field);
			
			// 使用Unsafe修改属性name的值
			unsafe.putObject(user, name_offset, name1);
			System.out.println("user2:" + user.toString());
			
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		
		return user;
    }
    
    /**
     * Unsafe作用一：操纵对象父类属性
     */
    @RequestMapping("/testUnsafe2")
    @ResponseBody
    public User testUnsafe2(String addr2, String name2, Integer age2) {
    	Man man = new Man();
    	man.setId(2);
    	man.setName("lisi");
    	man.setAge(20);
    	man.setAddr("北京");
		System.out.println("man1:" + man.toString());
		
		try {
			// 获取Unsafe类实例
			Field field = Unsafe.class.getDeclaredField("theUnsafe");
			field.setAccessible(true);
			Unsafe unsafe = (Unsafe)field.get(null);
			
			// 获取子类自己定义的属性addr
			Field addr_filed = man.getClass().getDeclaredField("addr");
			
			// 通过Unsafe.objectFieldOffset()方法获取非静态属性的值的内存偏移地址
			long addr_offset = unsafe.objectFieldOffset(addr_filed);
			
			// 使用Unsafe修改属性name的值
			unsafe.putObject(man, addr_offset, addr2);
			System.out.println("man2:" + man.toString());
			
			// 获取User类自己定义的属性name
			Field age_field = man.getClass().getField("age"); // age不是自己定义的属性，不能使用getDeclaredField方法
			
			// 通过Unsafe.objectFieldOffset()方法获取非静态属性name的值的内存偏移地址
			long age_offset = unsafe.objectFieldOffset(age_field);
			
			// 使用Unsafe修改属性name的值
			unsafe.putObject(man, age_offset, age2);
			System.out.println("man3:" + man.toString());
			
			// 获取User类自己定义的属性name（由于name是父类的private属性，子类无法获取，会抛出异常：NoSuchFieldException: name）
			Field name_field = man.getClass().getField("name");
			
			// 通过Unsafe.objectFieldOffset()方法获取非静态属性name的值的内存偏移地址
			long name_offset = unsafe.objectFieldOffset(name_field);
			
			// 使用Unsafe修改属性name的值
			unsafe.putObject(man, name_offset, name2);
			System.out.println("man4:" + man.toString());
			
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		
		return man;
    }
    
    
    class User {
    	private long id;
    	private String name;
    	public Integer age;

    	public long getId() {
    		return id;
    	}

    	public void setId(long id) {
    		this.id = id;
    	}

    	public String getName() {
    		return name;
    	}

    	public void setName(String name) {
    		this.name = name;
    	}

    	public Integer getAge() {
    		return age;
    	}

    	public void setAge(Integer age) {
    		this.age = age;
    	}

		@Override
		public String toString() {
			return "User [id=" + id + ", name=" + name + ", age=" + age + "]";
		}
    }
    
    class Man extends User {
    	private String addr;

		public String getAddr() {
			return addr;
		}

		public void setAddr(String addr) {
			this.addr = addr;
		}

		@Override
		public String toString() {
			return "[Man [id=" + super.getId() + ", name=" + super.getName() + ", age=" + super.getAge() + ", addr=" + addr + "]";
		}
    	
    }
    
}
